/**********************************************************************
*
*   Copyright(C) 2021
*   FileName:
*   Version : V0.0.1
*   Date    : 2024-04-20
*   Author  : Song.YuLong@chipsbank
*   Description:
*
*   Others:
*
*   Function List:
*   History      :
*
***********************************************************************/

#include "app_config.h"
#include "debug.h"

#include "lcd_driver_spi.h"
#include "lcd_draw_base.h"

// struct spilcd_t * spilcd_dev = NULL;

// 单色点阵屏操作
#if (LCD_BITS_PERPIXEL == 1)
#define LCD_FB_SIZE ((LCD_HEIGH * LCD_WIDTH)/8)

static volatile uint8_t xdata fb_buffer[LCD_WIDTH][(LCD_HEIGH/8)];   /* 显示缓存FB：单色点阵屏1个像素对应一个bit，一个字节8个像素点 */

/**
 * @brief 	清除屏幕
 * @param 	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_clear(uint8_t draw_mode)
{
	int x=0;
	int y=0;
	for (x=0; x<LCD_WIDTH; x++) {
		for (y=0; y<(LCD_HEIGH/8); y++) {
			fb_buffer[x][y] = 0x00;			
		}
	}

	if (E_DRAW_SC == draw_mode) {
		lcd_draw_update();
	}
}

/**
 * @brief 	填充屏幕
 * @param 	dot : 点的颜色值 1 或 0
 * @param 	draw_mode: E_LCD_DRAW_FB draw到FB
 * 					   E_LCD_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_fill(uint8_t dot, uint8_t draw_mode)
{
	int x=0;
	int y=0;
	for (x=0; x<LCD_WIDTH; x++) {
		for (y=0; y<(LCD_HEIGH/8); y++) {
			if (dot) {
				fb_buffer[x][y] = 0xFF;
			} else {
				fb_buffer[x][y] = 0x00;
			}
		}
	}

	if (E_DRAW_SC == draw_mode) {
		lcd_draw_update();
	}
}


/**
 * @brief 	画点
 * @param 	x: X坐标 
 * @param  	y: Y坐标
 * @param 	dot: 1 or 0
 * @param 	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_dot(int x, int y, uint8_t dot, uint8_t draw_mode)
{

	uint8_t Col = x;
	uint8_t Page = (y/8);
	uint8_t Bit  = (y%8);
	
	if ((x  >= LCD_WIDTH ) || (y >= LCD_HEIGH)) {
		//lcd_error(" X or Y Out Range\n");
		return;
	}
		
	if (dot) {
		fb_buffer[Col][Page] |= (u8)(0x1<<Bit); 
	} else {
		fb_buffer[Col][Page] &= (u8)(~(0x1<<Bit)); 
	}

	if (E_DRAW_SC == draw_mode) {
		#if ( (LCD_PANLE_MODULE == LCD_MODULE_UC1611S) )
		spilcd_spi_write((u8)LCD_CMD_SETPA_LSB(Page),  SPILCD_RW_CMD);	// 设置页地址
		spilcd_spi_write((u8)LCD_CMD_SETPA_MSB(Page),  SPILCD_RW_CMD);	// 设置页地址
		spilcd_spi_write((u8)LCD_CMD_SETCA_LSB(Col+1), SPILCD_RW_CMD);	// 设置列地址 低4bit
		spilcd_spi_write((u8)LCD_CMD_SETCA_MSB(Col+1), SPILCD_RW_CMD); 	// 设置列地址 高4bit
		spilcd_spi_write((u8)fb_buffer[Col][Page], 	   SPILCD_RW_DATA);	// 写入显示数据
		#else
		spilcd_spi_write((u8)LCD_CMD_SETPA(Page), 	 SPILCD_RW_CMD);	// 设置页地址
		spilcd_spi_write((u8)LCD_CMD_SETCA_LSB(Col), SPILCD_RW_CMD);	// 设置列地址 低4bit
		spilcd_spi_write((u8)LCD_CMD_SETCA_MSB(Col), SPILCD_RW_CMD); 	// 设置列地址 高4bit
		spilcd_spi_write((u8)fb_buffer[Col][Page], 	 SPILCD_RW_DATA);	// 写入显示数据
		#endif
	}

}

/**
 * @brief 	画水平直线
 * @param 	x: X坐标 
 * @param  	y: Y坐标
 * @param	width:水平线的宽度
 * @param 	dot: 1 or 0
 * @param 	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_hline(int x0, int y0, int width, uint8_t dot, uint8_t draw_mode)
{
	int w=0;

	for (w=0; w<width; w++) {
		lcd_draw_dot(x0+w, y0,  dot, draw_mode);	
	}
}

/**
 * @brief 	画垂直直线
 * @param 	x: X坐标 
 * @param  	y: Y坐标
 * @param	height: 垂直线的高度
 * @param 	dot: 1 or 0
 * @param 	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_vline(int x0, int y0,  int height, uint8_t dot, uint8_t draw_mode)
{
	int h=0;
	for (h=0; h<height; h++) {
		lcd_draw_dot(x0, y0+h,  dot, draw_mode);	
	}
}

/**
 * @brief	画线
 * @param	x1: 起点x坐标
 * @param	y1: 起点y坐标
 * @param 	x2: 终点x坐标
 * @param 	y2: 终点y坐标
 * @param	color: 颜色 0 or 1
 * @param	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_line(int x1, int y1, int x2, int y2, uint8_t color, uint8_t draw_mode)
{
	int16_t i=0;
	int16_t delta_x =0, delta_y = 0;
	int8_t incx =0,incy=0;
	int16_t distance = 0;
	int16_t t = 0;
	int16_t x=0,y=0;
	int16_t x_temp=0,y_temp=0;

	if (y1 == y2)
	{
		/* 画水平线 */
		for (i=0; i<x2-x1; i++) {
			lcd_draw_dot(i, y, color, draw_mode);
		}

	} else {
		/* 画斜线（Bresenham算法） */
		/* 计算两点之间在x和y方向的间距，得到画笔在x和y方向的步进值 */
		delta_x = x2 - x1;
		delta_y = y2 - y1;

		if (delta_x > 0) {
			/* 斜线 从左到右 */
			incx = 1;
		} else if (delta_x == 0) {
			/* 竖线 垂直斜线 */
			incx = 0;
		} else {
			/* 斜线 从右到左 */
			incx = -1;
			delta_x = -delta_x;
		}

		if (delta_y > 0) {
			/* 斜线   */
			incy = 1;
		} else if (delta_y == 0) {
			// 水平线 水平斜线
			incy = 0;
		} else {
			/* 斜线 */
			incy = -1;
			delta_y = -delta_y;
		}

		/* 计算画笔打点距离（取两个间距中的最大值）*/
		if (delta_x > delta_y) {
			distance = delta_x;
		} else {
			distance = delta_y;
		}

		/* 开始画线 */
		x = x1;
		y = y1;
		for (t=0; t<=distance+1; t++) {
			lcd_draw_dot(x, y, color, draw_mode);

			/* 判断离实际值最近的像素点 */
			x_temp += delta_x;
			if (x_temp > distance) {
				/* x方向越界，减去距离值 */
				x_temp -= distance;
				
				/* 在x方向递增打点 */
				x += incx;
			}

			y_temp += delta_y;
			if (y_temp > distance) {
				/* y方向越界，减去距离值 */
				y_temp -= distance;
				/* y方向递增打点 */
				y += incy;
			}
		}

	}
}


/**
 * @brief 	画矩形框
 * @param 	x: X坐标 
 * @param  	y: Y坐标
 * @param	width: 矩形框宽度
 * @param	height: 矩形框高度
 * @param 	dot: 1 or 0
 * @param 	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_rect(int x, int y, int width, int height, uint8_t dot, uint8_t draw_mode)
{
	// 顶边
	int X=0;
	int Y=0;
	for (X=x; X<(x+width); X++) {
		if ((X >= LCD_WIDTH)||(y>=LCD_HEIGH)) {
			continue;
		}
		lcd_draw_dot(X, y, dot, draw_mode);	
	}

	// 底边
	for (X=x; X<(x+width); X++) {
		if ((X >= LCD_WIDTH)||(y+height>=LCD_HEIGH)) {
			continue;
		}
		lcd_draw_dot(X, y+height, dot, draw_mode);	
	}

	// 左边
	for (Y=y; Y<(y+height); Y++) {
		if ((x >= LCD_WIDTH)||(Y >= LCD_HEIGH)) {
			continue;
		}
		lcd_draw_dot(x,Y, dot, draw_mode);	
	}

	// 右边
	for (Y=y; Y<(y+height); Y++) {
		if ((x+width-1 >= LCD_WIDTH)||(Y >= LCD_HEIGH)) {
			continue;
		}
		lcd_draw_dot(x+width-1, Y, dot, draw_mode);	
	}
}

/**
 * @brief 	填充矩形框
 * @param 	x: X坐标 
 * @param  	y: Y坐标
 * @param	width: 矩形框宽度
 * @param	height: 矩形框高度
 * @param 	dot: 1 or 0
 * @param 	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_fill_rect(int x, int y, int width, int height, uint8_t dot, uint8_t draw_mode)
{
	int X=0;
	int Y=0;
	for (Y=y; Y < y+height; Y++) {
		for (X=x; X < x+width; X++) {
			if ((X >= LCD_WIDTH)||(Y >= LCD_HEIGH)) {
				continue;
			}
			lcd_draw_dot(X, Y, dot, draw_mode);	
		}
	}
}

/*
 @brief 画空心圆
 @param x0 ：圆心X坐标
 @param y0 ：圆心Y坐标
 @param r  ：圆半径
 @param color ：颜色
 @param draw_mode ：E_DRAW_FB draw到FB
 				   E_DRAW_SC draw到SC
*/
void lcd_draw_circle(int x0, int y0, uint8_t r, uint8_t color, uint8_t draw_mode)
{
	/* Bresenham画圆算法 */
	int a, b;
    int di;
    a = 0;//x偏移变量
    b = r;//y偏移变量
    di = 3 - (r << 1);//算法决策参数，判别式(x+1)^2+y^2+(x+1)^2+(y-1)^2-2r^2,x=0,y=r代入此公式
 
	/* 圆在屏幕可视区域外，直接返回 */
	#if 0
	if (x0-r<0||x0+r>LCD_WIDTH || y0-r<0||y0+r>LCD_HEIGH) {
		return;
	}
	#endif

    while(a <= b)
    {
        //这几个都是镜像点，初始点为（x，y+r）
        lcd_draw_dot(x0 - b, y0 - a, color, draw_mode);
        lcd_draw_dot(x0 + b, y0 - a, color, draw_mode);
        lcd_draw_dot(x0 - a, y0 + b, color, draw_mode);
        lcd_draw_dot(x0 - b, y0 - a, color, draw_mode);
        lcd_draw_dot(x0 - a, y0 - b, color, draw_mode);
        lcd_draw_dot(x0 + b, y0 + a, color, draw_mode);
        lcd_draw_dot(x0 + a, y0 - b, color, draw_mode);
        lcd_draw_dot(x0 + a, y0 + b, color, draw_mode);
        lcd_draw_dot(x0 - b, y0 + a, color, draw_mode);
        a++;
 
        if(di < 0)
			di += 4 * a + 6;// 更新判别式 ，选择u点xi=x+1 yi=y
        else
        {
            di += 10 + 4 * (a - b);//更新判别式，选择d点xi=x+1 yi=y+1
            b--;
        }
 
        lcd_draw_dot(x0 + a, y0 + b, color, draw_mode);
    }
}



/**
 * @brief 	将buf数据写入到FB的制定区域
 * @param 	x:原点x坐标
 * @param 	y:原点y坐标 
 * @param 	width:buf数据宽度
 * @param 	height:buf数据高度
 * @param 	buf:单色点阵图像数据
 * @param	inverse:颜色 1:反色，0:正常
 * @param 	draw_mode: E_DRAW_FB draw到FB
 * 					   E_DRAW_SC draw到SC
 * @return 	none
*/
void lcd_draw_buf(int x, int y, int width, int height, uint8_t *buf, uint8_t inverse, uint8_t draw_mode)
{
	uint8_t dot;
	int Y,X;
	int h,w;
	int w_lines=0;
	int w_index=0;
	if ((x  >= LCD_WIDTH ) || (y >= LCD_HEIGH)) {
		//lcd_error(" X or Y Out Range\n");
		return;
	}
	
	for (h=0; h<height; h++) {
		Y=y+h; // Y:当前点Y坐标 = y + h  
		// lcd_info("Y:%d, h:%d, height:%d\n", Y, h, height);
	
		for (w=0; w<width; w++) {
			X=x+w; // X:当前点X坐标 = x + w  
			w_lines = (((width/8)+(width%8?1:0)) * h); // 当前处理行h  数据索引 如果width不是8的倍数，需要加1个字节
			w_index = w/8; // 当前处理行数据偏移量
			// lcd_debug("\t X:%d, w:%d, width:%d, w_index:%d, w_lines:%d, data_index:%d\n", X, w, width, w_index, w_lines, w_lines + w_index);
			
			dot = (buf[w_lines + w_index]); // 获取当前数据字节
			dot &= (0x80>>(w%8)); // 当前点 0/1

			if ((X >= LCD_WIDTH)||(Y >= LCD_HEIGH)) {
				continue;
			}

			// 反色
			if (E_DRAW_INVERSE == inverse) {
				dot = !dot;
			}
						
			lcd_draw_dot(X, Y, dot, draw_mode);
		}
	
	}
}


/**
 * @brief	更新屏幕数据，将FB数据写入到屏GRAM显示
 * @param 	none
 * @return 	none
*/
void lcd_draw_update(void)
{
	// uint32_t start_time = OS_JiffiesToMSecs(OS_GetJiffies());
	int Page=0;
	int Col=0;
#if ( (LCD_PANLE_MODULE == LCD_MODULE_UC1611S) )
	for (Page=0; Page<(LCD_HEIGH/8); Page++) {	
		spilcd_spi_write((u8)LCD_CMD_SETPA_LSB(Page), SPILCD_RW_CMD);	// 设置页地址
		spilcd_spi_write((u8)LCD_CMD_SETPA_MSB(Page), SPILCD_RW_CMD);	// 设置页地址
		spilcd_spi_write((u8)LCD_CMD_SETCA_LSB(Col+1),  SPILCD_RW_CMD);	// 设置列地址 低4bit
		spilcd_spi_write((u8)LCD_CMD_SETCA_MSB(Col+1),  SPILCD_RW_CMD); // 设置列地址 高4bit

		for(Col=0; Col<LCD_WIDTH; Col++) {			
			spilcd_spi_write((u8)fb_buffer[Col][Page], SPILCD_RW_DATA);	// 写入显示数据
		}
	}
#else
	for (Page=0; Page<8; Page++) {	
		for(Col=0; Col<LCD_WIDTH; Col++) {			
			spilcd_spi_write((u8)LCD_CMD_SETPA(Page), 	 SPILCD_RW_CMD);	// 设置页地址
			spilcd_spi_write((u8)LCD_CMD_SETCA_LSB(Col), SPILCD_RW_CMD);	// 设置列地址 低4bit
			spilcd_spi_write((u8)LCD_CMD_SETCA_MSB(Col), SPILCD_RW_CMD); 	// 设置列地址 高4bit
			spilcd_spi_write((u8)fb_buffer[Col][Page], 	 SPILCD_RW_DATA);	// 写入显示数据
		}
	}
#endif
	// lcd_debug("--->drv_lcd_update_screen time: %d ms\n", OS_JiffiesToMSecs(OS_GetJiffies()-start_time));
}

/**
 * @brief	LCD背光控制
 * @param	state: 1,背光亮，0,背光灭
 * @return	void
 * @note	
*/
void lcd_backlight_control(u8 state)
{
    // drv_spilcd_backlight_onoff(state);
}

/**
 * @brief	LCD draw初始化
 * @param	dev:参考@struct spilcd_t
 * @return	void
 * @note	
*/
void lcd_draw_init()
{
	log_d("lcd_draw_init\n");
    // TODO: LCD初始化
    spilcd_spi_init();	
	
#if 0
	lcd_draw_fill(E_DRAW_0, E_DRAW_FB);	// 清除BUF
	lcd_draw_fill_rect(0, 0, 10, 10, E_DRAW_1, E_DRAW_FB);
	lcd_draw_fill_rect(30, 20, 15, 15, E_DRAW_1, E_DRAW_FB);
	lcd_draw_update();
#endif

#if 0   /* for test lcd_draw */
    lcd_draw_rect(0, 0, 50, 50, E_DRAW_1, E_DRAW_FB);
    lcd_draw_hline(10, 10, 100, E_DRAW_1, E_DRAW_FB);
    lcd_draw_vline(20, 0, 100, E_DRAW_0, E_DRAW_FB);
    lcd_draw_update();

    // lcd_draw_fill_rect(10, 10, 80, 50, E_DRAW_1, E_DRAW_SC);
#endif
}
#else

#endif




#if 0 // for test
void lcd_draw_demo_test(void)
{
    struct spilcd_t lcd;
    lcd.lcd_ds = LCD_DS_PORT;
    lcd.lcd_cs = LCD_CS_PORT;
    lcd.lcd_reset = LCD_RESET_PORT;
    lcd.lcd_power = LCD_POWER_CTRL_PORT;
    lcd.power_level = LCD_POWER_CTRL_LEVEL;    // 供电有效电平
    lcd.lcd_light = LCD_BACKLIGHT_PORT;
    lcd.light_level = LCD_BACKLIGHT_LEVEL;     // 背光有效电平

    lcd.width = LCD_WIDTH;
    lcd.height = LCD_HEIGH;

    // TODO:初始化LCD显示屏
    lcd_draw_init(&lcd);

    lcd_draw_rect(0, 0, 50, 50, E_DRAW_1, E_DRAW_FB);
    lcd_draw_hline(10, 10, 100, E_DRAW_1, E_DRAW_FB);
    lcd_draw_vline(20, 0, 100, E_DRAW_0, E_DRAW_FB);
    lcd_draw_update();

    lcd_draw_rect_fill(10, 10, 80, 50, E_DRAW_1, E_DRAW_SC);

    lcd_draw_clear();
    lcd_draw_bmp(0,0,128,64, (uint8_t*)IMG_QQ, 0, 0);
    lcd_draw_update();
    // TODO:开启背光 
    lcd_backlight_control(BLK_ON);
}
#endif